大家好,今天來到第六天了~完成1/5了,必須說參加鐵人賽還都完賽的人,真的很棒很有毅力,花自己工作之餘的休息時間來分享自己的學習歷程,這邊我給自己一個肯定哈哈哈哈!!我會努力把30天寫完的!!
今天這個題目呢,是我去年在資策會的時候想要自己練習做資料分析去Kaggle找到的一個題目,它是一堆犯罪紀錄,而我們要拿這些資料去預測它的test資料集是哪種犯罪類型,很好玩吧,是一個多分類的問題,不像前幾天做的都是二分類的問題。
kaggle傳送門。
第一步一定是導入我們的資料啦~我們一樣用pandas套件的read_csv來導入資料。
import pandas as pd
train=pd.read_csv('./train.csv')
test=pd.read_csv('./test.csv')
再來我們看看資料型態長怎樣。
print(train.head(5))
我們來解釋一下它的各個資料欄位的意思,在train資料裡面總共有9個欄位,分別為:
1. Dates:犯罪事件的時間戳。
2. Category:犯罪事件的類型。(也就是我們要預測的Y)
3. Descript:對於犯罪的描述。
4. DayOfWeek:犯罪是在星期幾。
5. PdDistrict:警察局管轄區域名稱。
6. Resolution:犯罪是如何被解決的。
7. Address:犯罪發生的大致街道地址。
8. X:犯罪位置的經度。
9. Y:犯罪位置的緯度。
接下來我們看看test資料裡面有哪些特徵欄位。
print(test.columns)
分別為:
1. Id:編號ID。
2. Dates:犯罪事件的時間戳。
3. DayOfWeek:犯罪是在星期幾。
4. PdDistrict:警察局管轄區域名稱。
5. Address:犯罪發生的大致街道地址。
6. X:犯罪位置的經度。
7. Y:犯罪位置的緯度。
所以我們可以先做第一件事情就是把沒出現在test的特徵欄位刪除,所以我們將train裡面的"Descript"及"Resolution"這兩個特徵刪除。"Category"則是我們訓練時需要用到的應變數。
train.drop(['Descript','Resolution'],inplace=True,axis=1)
print(train.head(5))
查看有沒有缺失值,發現資料並無缺失值。
print(train.isnull().sum())
print(test.isnull().sum())
train test
接下來,在Dates的地方,我想把這個欄位再分的更細一點,年、月、時和分給區隔開來,日期我沒有分出來,我認為日期對我們要預測的應變數影響不大。還有Address的部分,若有含街道block的部分,我把它顯示為布林值。這裡DayOfWeek我們自己再做一次,怕原本資料寫錯,且原資料給的星期幾是類別變數,我們也直接將它轉成虛擬變數。
def build_datetime_and_block(df):
df['Dates'] = pd.to_datetime(df['Dates'])
df['Date'] = df['Dates'].dt.date
df['Hour'] = df['Dates'].dt.hour
df['Minute'] = df['Dates'].dt.minute
df['DayOfWeek'] = df['Dates'].dt.weekday
df['Month'] = df['Dates'].dt.month
df['Year'] = df['Dates'].dt.year
df['Block'] = df['Address'].str.contains('block', case=False)#case預設=True,表示區分大小寫。
return df
train = build_datetime_and_block(train)
test = build_datetime_and_block(test)
我們已經把Dates和Address給分的更細了,那這些特徵就不需要了,將他們刪除。
train.drop(['Address','Dates','Date'],inplace=True,axis=1)
test.drop(['Address','Dates','Date'],inplace=True,axis=1)
print(train.head(5))
print(test.head(5))
train
test
處理完上面的特徵,我們來看看剩下"PdDistrict"和經緯度("X"、"Y")沒有動到,先來看看"PdDistrict"有沒有其他的問題,已經檢視過沒有缺失值了。
print(train.PdDistrict.unique())
看起來也沒有其他問題。
再來看看經緯度吧!
這裡我們會用到geopandas這個套件,我自己安裝的時候是有遇到一些問題,可以參考這裡去安裝。
from shapely.geometry import Point
import geopandas as gpd
def create_gdf(df):
gdf = df.copy()
gdf['Coordinates'] = list(zip(gdf.X, gdf.Y))
gdf.Coordinates = gdf.Coordinates.apply(Point)
gdf = gpd.GeoDataFrame(
gdf, geometry='Coordinates', crs={'init': 'epsg:4326'})
return gdf
train_gdf = create_gdf(train)
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
ax = world.plot(color='white', edgecolor='black')
train_gdf.plot(ax=ax, color='red')
plt.show()
可以發現最上面那個紅點明顯偏離了,代表有經緯度是給錯的。
我們將經緯度照順序列出來,看到X = -120.5和Y = 90.0這兩個變數屬於離群值。
print(sorted(list(train.X.unique()),reverse=True))
print(sorted(list(train.Y.unique()),reverse=True))
X Y
先觀察筆數多寡,可以發現當X = -120.5時,Y = 90.0,train都是67筆,而test是76筆。
wrongxy = lambda df : len(df[(df['X'] == -120.5) & (df['Y'] == 90.0)])
print(wrongxy(train))
print(wrongxy(test))
wrongxy = lambda df : len(df[(df['X'] == -120.5)])
print(wrongxy(train))
print(wrongxy(test))
wrongxy = lambda df : len(df[(df['Y'] == 90.0)])
print(wrongxy(train))
print(wrongxy(test))
我們可選擇刪除或是改動值的方式,這邊我選擇依照PdDistrict的經緯度的中位數去改這些值。
def fix_gps(df):
n = 0
d = df[(df['X'] == -120.5) & (df['Y'] == 90.0)]
for idx, row in d.iterrows():
district = row['PdDistrict']
xys = df[df['PdDistrict'] == district][['X', 'Y']]
#print("PdDistrict:", district)
df.loc[idx, ['X']] = xys['X'].median()
df.loc[idx, ['Y']] = xys['Y'].median()
#print(df.loc[idx, ['X']].values[0], df.loc[idx, ['Y']].values[0])
n = n + 1
print('更動幾筆資料:', n)
fix_gps(train)
fix_gps(test)
今天主要對資料做清洗,對於每個特徵,都較詳細的去處理他們,並且有搭配到用地圖去看經緯度資料是否有誤。資料前處理部分剩下一部分,主要是這次的資料很多為類別變數,我們需要幫它轉換成虛擬變數,文字變成數字,這樣才能丟進模型建模,那我們明天就來處理剩下的部分吧!!這次的模型,除了用之前的sklearn套件以外,還會嘗試用tensorflow去建立神經網路來建模,開始要接觸深度學習囉!!
那我們明天見~